﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using Asistente.Managers;
using Asistente.Model.COSMIC;
using Asistente.Model.General;
using Asistente.Model.IFPUG;


namespace Asistente.Model.Representation
{
    //Representa la aplciacion que quiere medir el usuario, contiene un conjunto de casos de uso,
    //un nombre, descripcion, tiempo que ha llevado medirla, su tamano funcional en IFPUG y en COSMIC.

    public class Application : DependencyObject,IElement
    {
        public String Name { get; set; }
        public String Description { get; set; }
        public int Hours { get; set; }
        public int Minutes { get; set; }
        public int Seconds { get; set; }
        public int IfpugSize { get; set; }
        public int CosmicSize { get; set; }

        private Collection<UseCase> useCases;
        public Collection<UseCase> UseCases
        {
            get { return useCases; }
            set { useCases = value;}
        }
       

        private Collection<Entity> entities;
        public Collection<Entity> Entities
        {
            get { return entities; }
            set { entities = value;}
        }

        public Application()
        {
            useCases = new Collection<UseCase>();
            entities = new Collection<Entity>();

            Name = Numerator.Instance.GetName(GetType());
            Description = Name;

            Hours = 0;
            Minutes = 0;
            Seconds = 0;
        }

        internal string GetTime()
        {
            return Hours + ":" + Minutes + ":" + Seconds;
        }

        internal void DeleteEntity(Entity entity)
        {
            Entities.Remove(entity); 
        }

        public void DeleteUseCase(UseCase useCase)
        {
            if (useCases.Contains(useCase))
                useCases.Remove(useCase);
        }

        public void DeleteScreen(Screen screen)
        {
            foreach (UseCase uc in UseCases)
            {
                uc.DeleteScreen(screen);
            }
        }

        public void DeletePanel(Panel panel)
        {
            foreach (UseCase useCase in UseCases)
            {
                useCase.DeletePanel(panel);
            }
        }

        public void AddUseCase(UseCase useCase)
        {
            UseCases.Add(useCase);
        }

        public UseCase NewUseCase(UseCasePattern pattern, Entity master = null, Entity detail = null,
                                  UseCaseComplexity complexity = UseCaseComplexity.Simple,
                                  UseCaseCardinality cardinality = UseCaseCardinality.One,
                                  UseCaseLayout layout = UseCaseLayout.OnePanel)
        {
            //En caso de ser WW se comporta distinto, se crean alta baja modif y el panel de ww
            if (pattern != UseCasePattern.WorkWith)
            {
                UseCase useCase = UseCaseManager.Instance.NewUseCase(pattern, master, detail, complexity,
                                                                     cardinality, layout);
                UseCases.Add(useCase);
                return useCase;
            }
            else
            {
                //Se crean y agregan los casos de uso
                UseCase wwUseCase = UseCaseManager.Instance.NewUseCase(pattern, master, detail, complexity,
                                                                       cardinality, layout);
                UseCases.Add(wwUseCase);

                UseCase newUseCase = UseCaseManager.Instance.NewUseCase(UseCasePattern.New, master, detail, complexity,
                                                                        cardinality, layout);
                UseCases.Add(newUseCase);

                UseCase deleteUseCase = UseCaseManager.Instance.NewUseCase(UseCasePattern.LogicDelete, master, detail,
                                                                           complexity,
                                                                           cardinality, layout);
                UseCases.Add(deleteUseCase);

                UseCase updateUseCase = UseCaseManager.Instance.NewUseCase(UseCasePattern.Update, master, detail,
                                                                           complexity,
                                                                           cardinality, layout);
                UseCases.Add(updateUseCase);

                //Se hacen las referencias
                wwUseCase.NewAction(newUseCase);
                wwUseCase.NewAction(deleteUseCase);
                wwUseCase.NewAction(updateUseCase);

                return wwUseCase;
            }
        }

        public Entity NewEntity(String name = null)
        {
            Entity entity = new Entity();
            if (name == null)
            {
                name = entity.Name = Numerator.Instance.GetName(entity.GetType());
            }
            entity.Name = name;
            Entities.Add(entity);
            return entity;
        }

        public void ChangeUseCasePattern(UseCase useCase, UseCasePattern useCasePattern)
        {
            useCase.Pattern = useCasePattern;
        }

        public void CloneUseCase(UseCase useCase)
        {
            UseCases.Add(useCase.Clone());
        }

         /// <summary>
        /// Returns a list containing the hierarchical higher data of a target element
        /// </summary>
        /// <param name="target"></param>
        /// <returns></returns>
        public List<Element> getHierarchicalHigherData(Element target)
        {
            List<Element> hierarchy = new List<Element>();
            
            while(target!=null){

                hierarchy.Add(target);
                target=GetParent(target);
            }
            hierarchy.Reverse();
            return hierarchy;
        }

        /// <summary>
        /// Returns the parent element of a target element
        /// </summary>
        /// <param name="target"></param>
        /// <returns></returns>
        private Element GetParent(Element target)
        {
            if (target.GetType().Equals(typeof(Screen)))
            {
                foreach (UseCase useCase in this.useCases)
                {
                    foreach (Screen screen in useCase.Screens)
                    {
                        if (screen.Equals((target as Screen)))
                        {
                            return useCase;
                        }
                    }
                }
            }
            else if (target.GetType().Equals(typeof(Panel)))
            {
                foreach (UseCase useCase in this.useCases)
                {
                    foreach (Screen screen in useCase.Screens)
                    {
                        foreach (Panel panel in screen.Panels)
                        {
                            if (panel.Equals((target as Panel)))
                            {
                                return screen;
                            } 
                        }

                    }
                }
            }

            return null;
        }
        
        #region IfpugModel Converter

        //El modelo de la aplicacion se convierte a ifpug. Se genera un IfpugModel, que contiene 
        //una lista de TransformedEntity
        //una lista de TransformedUseCase
        //una lista de TransformedControl

        //Por lo tanto el proceso de convertir la aplicacion consiste en generar un IfpugModel 
        //que resulta de transformar todos los casos de uso definidos por el medior, todos las
        //entidades definidas por el medidor y todos los controles que generan proceso transaccionales.

        public IMeasurable ConvertToIfpugModel()
        {
            IfpugModel measurementModel = new IfpugModel();

            //Se setea la aplicacion que medimos
            measurementModel.App = this;

            //Para cada caso de uso, se convierte
            foreach (UseCase useCase in UseCases)
            {
                //Se convierte el caso de uso
                useCase.ConvertToIfpugModel(measurementModel);
            }

            //Se convierten cada una de la entidades
            foreach (Entity entity in Entities)
            {
                entity.ConvertToIfpugModel(measurementModel);
            }

            //Se convierten los contoles que generan funciones de transaccion
            foreach (Control control in GetControlsGenerateTransactionalFunctions())
            {
                control.ConvertToIfpugModel(measurementModel);
            }

            return measurementModel;
        }

        //Se retorna la lista de controles del tipo Autocomplete o DropDownChooser de toda la aplicacion ya que 
        //son los unicos dos tipos de controles que generan funciones transaccionales.

        private IEnumerable<Control> GetControlsGenerateTransactionalFunctions()
        {
            List<Control> controls = new List<Control>();

            foreach (var useCase in UseCases)
            {
                foreach (var screen in useCase.Screens)
                {
                    //Para todos los controles de los paneles
                    foreach (var panel in screen.Panels)
                    {
                        foreach (var control in panel.Controls)
                        {
                            if (control.ControlPattern == ControlPattern.Autocomplete || control.ControlPattern == ControlPattern.DropDownChooser)
                            {
                                controls.Add(control);
                            }
                        }
                    }

                    //Para todos los controles de los paneles de master details
                    foreach (var masterDetail in screen.MasterDetails)
                    {
                        if (masterDetail.Master != null) { 
                            //Master
                            foreach (var control in masterDetail.Master.Controls)
                            {
                                if (control.ControlPattern == ControlPattern.Autocomplete || control.ControlPattern == ControlPattern.DropDownChooser)
                                {
                                    controls.Add(control);
                                }
                            }
                        }

                        //Details
                        foreach (var panel in masterDetail.Details)
                        {
                            foreach (var control in panel.Controls)
                            {
                                if (control.ControlPattern == ControlPattern.Autocomplete || control.ControlPattern == ControlPattern.DropDownChooser)
                                {
                                    controls.Add(control);
                                }
                            }
                        }
                    }
                }
            }
            return controls;
        }

        #endregion

        #region CosmicModel Converter

        public IMeasurable ConvertToCosmicModel()
        {
            CosmicModel measurementModel = CosmicConverter.Instance.Convert(this);
            return measurementModel;
        }

        #endregion
    }
}